using System.Dynamic;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MyTools;
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Unity.Mathematics;
using UnityEngine.UI;

public class AgentChat : MonoBehaviour
{
    public InputField userinput;
    public InputField nameinput;
    public GameObject toPutWorkflowCard;
    
    public GameObject prefab_workflowCard;
    public GameObject prefab_msg;




    Cooldown cd;
    ClientWebSocket ws;

    // Start is called before the first frame update
    async void Start()
    {
        cd = new Cooldown(5f);
        ws = new ClientWebSocket();
        
        try
        {
            await ws.ConnectAsync(new Uri("ws://127.0.0.1:3002"), CancellationToken.None);
            Debug.Log("WebSocketClient for Agent process Starting");
            // Start receiving messages in a separate task
            _ = ReceiveMessagesAsync();
        }
        catch (Exception ex)
        {
            Debug.LogWarning($"WebSocket connection error: {ex.Message}");
        }
    }

    private void Update()
    {
        cd.Update(Time.deltaTime);
        if (cd.Check())
        {
            cd.Used();
            GetAgentProcess();
        }
    }

    public async void GetAgentProcess()
    {
        try
        {
        if (ws == null || ws.State != WebSocketState.Open)
        {
            ws = new ClientWebSocket();
            await ws.ConnectAsync(new Uri("ws://127.0.0.1:3002"), CancellationToken.None);
            Debug.Log("WebSocketClient for Agent process Starting");
        }

            ArraySegment<byte> bytesToSend = new ArraySegment<byte>(Encoding.UTF8.GetBytes("{\"type\":\"getProcess\"}"));
            await ws.SendAsync(bytesToSend, WebSocketMessageType.Text, true, CancellationToken.None);
        }
        catch (Exception ex)
        {
            Debug.LogWarning($"Error sending message: {ex.Message}");
        }
    }

    public void OnClickStartBtn(){
        StartProcess( userinput.text );
    }

    public async void StartProcess(string workingrequest){
        
        try
        {
        if (ws == null || ws.State != WebSocketState.Open)
        {
            ws = new ClientWebSocket();
            await ws.ConnectAsync(new Uri("ws://127.0.0.1:3002"), CancellationToken.None);
            Debug.Log("WebSocketClient for Agent process Starting");
        }

            ArraySegment<byte> bytesToSend = new ArraySegment<byte>(Encoding.UTF8.GetBytes("{\"type\":\"startMakeGurouce\",\"message\":\""+userinput.text+"\",\"name\":\""+nameinput.text+"\"}"));
            await ws.SendAsync(bytesToSend, WebSocketMessageType.Text, true, CancellationToken.None);
        }
        catch (Exception ex)
        {
            Debug.LogWarning($"Error sending message: {ex.Message}");
        }
    }

    private void ProcessMessage(string message)
    {
        //将 toPutWorkflowCard 的儿子全部清除
        for (int i = toPutWorkflowCard.transform.childCount - 1; i >= 0; i--)
        {
            // Get the child GameObject
            GameObject child = toPutWorkflowCard.transform.GetChild(i).gameObject;

            // Destroy the child GameObject
            Destroy(child);
        }
        

        var result = JsonUtility.FromJson<NetData>(message);
        
        if (result.type == "process"){
            //WorkFlow的所有子物体
            if (result.data == null || result.data=="None" || result.data.Length<=1){ return; }
            Debug.Log($"Processing result.data: {result.data}");
            string[] tasks = result.data.Split("$TASKTASK$");
            
            //var data = JsonUtility.FromJson<TaskDataListWrapper>("{\"items\":"+result.data+"}");
            foreach (var task in tasks){
                string[] infos = task.Split("$TOPICTOPIC$");
                
                var card = Instantiate(prefab_workflowCard, toPutWorkflowCard.transform);
                card.GetComponent<WorkFlowCardReferer>().topic.GetComponent<Text>().text = infos[0];
                AddMsg(card.GetComponent<WorkFlowCardReferer>().msgContainer,infos[1]);
            }


        }else if(result.type == "started"){
            Debug.Log("Started !");
        }else{
            Debug.Log("Error type happened !");
        }

        // Implement your logic to handle incoming messages here
    }
    private void AddMsg(GameObject msgContainer,string msgs){
        Debug.Log("AddMsg !"+msgs);
        string[] msg_list = msgs.Split("$MEMORYMEMORY$");
        foreach (var msg in msg_list){
            var msg_card = Instantiate(prefab_msg, msgContainer.transform);
            msg_card.GetComponent<WorkFlowCardMsgReferer>().text.GetComponent<Text>().text =  msg;
        }
    }










    private async void OnApplicationQuit()
    {
        if (ws != null && ws.State == WebSocketState.Open)
        {
            await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
            ws.Dispose();
        }
    }
    
    private async Task ReceiveMessagesAsync()
    {
        var buffer = new byte[1024 * 4]; // Buffer size for incoming data

        while (ws != null && ws.State == WebSocketState.Open)
        {
            WebSocketReceiveResult result = null;
            var stringBuilder = new StringBuilder();

            try
            {
                do
                {
                    result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    if (result.MessageType == WebSocketMessageType.Close)
                    {
                        await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
                        Debug.Log("WebSocket connection closed.");
                        return;
                    }

                    // Append received data to the string builder
                    var messagePart = Encoding.UTF8.GetString(buffer, 0, result.Count);
                    stringBuilder.Append(messagePart);

                } while (!result.EndOfMessage);

                // Process the complete message
                string message = stringBuilder.ToString();
                Debug.Log($"Received message: {message}");
                ProcessMessage(message);
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error receiving message: {ex.Message}");
                break;
            }
        }
    }

}

[System.Serializable]
public class NetData
{
    public string type;
    public string data;
}

[System.Serializable]
public class TaskData
{
    [SerializeField]
    public string topic { get; set; }
    [SerializeField]
    public string memory { get; set; }
    [SerializeField]
    public string finish { get; set; }
}
[Serializable]
public class TaskDataListWrapper
{
    public List<TaskData> items { get; set; }
}

// List<T>
[Serializable]
public class Serialization<T>
{
    [SerializeField]
    List<T> target;
    public List<T> ToList() { return target; }

    public Serialization(List<T> target)
    {
        this.target = target;
    }
}

// Dictionary<TKey, TValue>
[Serializable]
public class Serialization<TKey, TValue> : ISerializationCallbackReceiver
{
    [SerializeField]
    List<TKey> keys;
    [SerializeField]
    List<TValue> values;

    Dictionary<TKey, TValue> target;
    public Dictionary<TKey, TValue> ToDictionary() { return target; }

    public Serialization(Dictionary<TKey, TValue> target)
    {
        this.target = target;
    }

    public void OnBeforeSerialize()
    {
        keys = new List<TKey>(target.Keys);
        values = new List<TValue>(target.Values);
    }

    public void OnAfterDeserialize()
    {
        var count = Math.Min(keys.Count, values.Count);
        target = new Dictionary<TKey, TValue>(count);
        for (var i = 0; i < count; ++i)
        {
            target.Add(keys[i], values[i]);
        }
    }
}